<template>
  <div
    ref="containerRef"
    class="virtual-editable-table"
    :class="{
      'is-contenteditable': editConfig?.trigger === 'contenteditable'
    }"
  >
    <!-- 如果启用 contenteditable 模式，容器需要设置 contenteditable -->
    <div
      v-if="editConfig?.trigger === 'contenteditable'"
      class="table-content-wrapper"
      contenteditable="true"
      @focusin="handleFocusIn"
      @focusout="handleFocusOut"
      @keydown="handleKeyDown"
    >
      <DynamicScroller
        ref="scrollerRef"
        :items="tableData"
        :min-item-size="minItemSize"
        :key-field="rowConfig.keyField"
        class="virtual-scroller"
      >
        <template #default="{ item, index, active }">
          <DynamicScrollerItem
            :item="item"
            :active="active"
            :size-dependencies="[item.content?.length, item._editing]"
            :data-id="item[rowConfig.keyField]"
            :data-index="index"
            class="virtual-table-row"
            :class="getRowClass(item, index)"
          >
            <div class="row-content">
              <!-- 渲染列内容 -->
              <div
                v-for="column in columns"
                :key="column.field"
                class="virtual-table-cell"
                :class="`cell-${column.field}`"
                :style="getCellStyle(column)"
              >
                <div
                  :field="column.field"
                  class="cell-content"
                  :class="{
                    'is-editable': column.editable !== false,
                    'is-editing': isEditing(item)
                  }"
                  v-html="getCellContent(item, column)"
                ></div>
              </div>
            </div>
          </DynamicScrollerItem>
        </template>
      </DynamicScroller>
    </div>

    <!-- 非 contenteditable 模式 -->
    <div v-else class="table-content-wrapper">
      <DynamicScroller
        ref="scrollerRef"
        :items="tableData"
        :min-item-size="minItemSize"
        :key-field="rowConfig.keyField"
        class="virtual-scroller"
      >
        <template #default="{ item, index, active }">
          <DynamicScrollerItem
            :item="item"
            :active="active"
            :size-dependencies="[item.content?.length, item._editing]"
            :data-id="item[rowConfig.keyField]"
            :data-index="index"
            class="virtual-table-row"
            :class="getRowClass(item, index)"
            @dblclick="handleDoubleClick(item, $event)"
          >
            <div class="row-content">
              <!-- 渲染列内容 -->
              <div
                v-for="column in columns"
                :key="column.field"
                class="virtual-table-cell"
                :class="`cell-${column.field}`"
                :style="getCellStyle(column)"
              >
                <div
                  :field="column.field"
                  class="cell-content"
                  :class="{
                    'is-editable': column.editable !== false,
                    'is-editing': isEditing(item)
                  }"
                >
                  <!-- 使用插槽或默认渲染 -->
                  <slot :name="column.field" :row="item" :column="column" :index="index">
                    {{ getCellContent(item, column) }}
                  </slot>
                </div>
              </div>
            </div>
          </DynamicScrollerItem>
        </template>
      </DynamicScroller>
    </div>

    <!-- 加载提示 -->
    <div v-if="loading" class="loading-mask">
      <div class="loading-spinner">加载中...</div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, nextTick, onMounted, onUnmounted, watch } from 'vue'
import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
import { useEditHandler } from './composables/useEditHandler'
import { useFocusManager } from './composables/useFocusManager'
import type { EditConfig, SaveAdapter, RowConfig } from '../index'

interface Column {
  field: string
  title: string
  width?: number | string
  minWidth?: number
  editable?: boolean
  sortable?: boolean
}

interface Props {
  data: any[]
  columns?: Column[]
  rowConfig?: RowConfig
  editConfig?: EditConfig
  saveAdapter?: SaveAdapter | null
  loading?: boolean
  rowClassName?: (row: any, index: number) => string
  minItemSize?: number
}

const props = withDefaults(defineProps<Props>(), {
  data: () => [],
  columns: () => [],
  rowConfig: () => ({ keyField: 'id' }),
  editConfig: () => ({ trigger: 'contenteditable', mode: 'row' }),
  saveAdapter: null,
  loading: false,
  minItemSize: 50
})

const emit = defineEmits<{
  'edit-activated': [{ row: any; field?: string }]
  'edit-closed': [{ row: any; field?: string; changed: boolean; result?: any; error?: any }]
  'save-success': [{ row: any; field?: string; result: any }]
  'save-error': [{ row: any; field?: string; error: any }]
  'edit-cancelled': [{ row: any }]
  'row-edit': [{ row: any; field?: string }]
  'current-change': [{ row: any }]
  'update:data': [any[]]
}>()

// 模板引用
const containerRef = ref<HTMLElement>()
const scrollerRef = ref()

// 响应式数据
const tableData = ref(props.data)
const currentRow = ref<any>(null)

// 监听数据变化
watch(
  () => props.data,
  (newData) => {
    tableData.value = newData
  },
  { deep: true }
)

// 获取列配置
const columns = computed<Column[]>(() => {
  // 如果没有传入列配置，尝试从第一行数据推断
  if (props.columns.length > 0) {
    return props.columns
  }

  if (tableData.value.length > 0) {
    const firstRow = tableData.value[0]
    return Object.keys(firstRow)
      .filter((key) => !key.startsWith('_') && key !== props.rowConfig.keyField)
      .map((key) => ({
        field: key,
        title: key,
        editable: true
      }))
  }

  return []
})

// 编辑处理器
const editHandler = useEditHandler(props.editConfig!, props.saveAdapter, emit)

// 焦点管理器
const focusManager = useFocusManager(editHandler, props.editConfig?.debounceTime || 50)

// 获取行样式类
const getRowClass = (row: any, index: number): string => {
  const classes = []

  if (editHandler.isEditing(row)) {
    classes.push('is-editing')
  }

  if (currentRow.value && editHandler.getRowKey(currentRow.value) === editHandler.getRowKey(row)) {
    classes.push('is-current')
  }

  if (props.rowClassName) {
    const customClass = props.rowClassName(row, index)
    if (customClass) {
      classes.push(customClass)
    }
  }

  return classes.join(' ')
}

// 获取单元格样式
const getCellStyle = (column: Column): Record<string, any> => {
  const style: Record<string, any> = {}

  if (column.width) {
    style.width = typeof column.width === 'number' ? `${column.width}px` : column.width
    style.flexShrink = 0
  }

  if (column.minWidth) {
    style.minWidth = `${column.minWidth}px`
  }

  return style
}

// 获取单元格内容
const getCellContent = (row: any, column: Column): string => {
  const value = row[column.field]
  return value !== null && value !== undefined ? String(value) : ''
}

// 检查行是否正在编辑
const isEditing = (row: any): boolean => {
  return editHandler.isEditing(row)
}

// 处理双击编辑
const handleDoubleClick = (row: any, event: MouseEvent): void => {
  if (props.editConfig?.trigger !== 'dblclick') return

  const target = event.target as HTMLElement
  const field = target.closest('[field]')?.getAttribute('field')

  if (field) {
    editHandler.startEdit(row, field)
  }
}

// 事件处理
const handleFocusIn = (event: FocusEvent): void => {
  focusManager.handleFocusIn(event)
}

const handleFocusOut = (event: FocusEvent): void => {
  focusManager.handleFocusOut(event)
}

const handleKeyDown = (event: KeyboardEvent): void => {
  focusManager.handleKeyDown(event)
}

// 公开的方法
const scrollToRow = (row: any): void => {
  if (!scrollerRef.value) return

  const index = tableData.value.findIndex(
    (item) => editHandler.getRowKey(item) === editHandler.getRowKey(row)
  )

  if (index >= 0) {
    scrollerRef.value.scrollToItem(index)
  }
}

const setCurrentRow = (row: any): void => {
  currentRow.value = row
  emit('current-change', { row })
}

const saveRow = async (row: any): Promise<void> => {
  await editHandler.endEdit(row, undefined, true)
}

const cancelEdit = (row: any): void => {
  editHandler.cancelEdit(row)
}

const startEdit = (row: any, field?: string): void => {
  editHandler.startEdit(row, field)

  // 如果指定了字段，设置焦点
  if (field) {
    focusManager.focusCell(row, field)
  }
}

const isUpdateByRow = (row: any, field?: string): boolean => {
  return editHandler.hasChanged(row, field)
}

const isEditByRow = (row: any): boolean => {
  return editHandler.isEditing(row)
}

// 暴露方法给父组件
defineExpose({
  scrollToRow,
  setCurrentRow,
  saveRow,
  cancelEdit,
  startEdit,
  isUpdateByRow,
  isEditByRow,
  saveAll: editHandler.saveAll,
  cancelAll: editHandler.cancelAll
})

// 生命周期
onMounted(() => {
  // 组件挂载后的初始化
})

onUnmounted(() => {
  // 清理资源
  editHandler.clearAll()
  focusManager.cleanup()
})
</script>

<style scoped>
.virtual-editable-table {
  position: relative;
  height: 100%;
  border: 1px solid #e0e0e0;
  border-radius: 4px;
  overflow: hidden;
}

.table-content-wrapper {
  height: 100%;
  outline: none;
}

.table-content-wrapper[contenteditable='true'] {
  &:focus {
    outline: none;
  }

  &::selection {
    background-color: rgba(0, 100, 255, 0.2);
  }
}

.virtual-scroller {
  height: 100%;
}

.virtual-table-row {
  border-bottom: 1px solid #f0f0f0;
  transition: background-color 0.2s;

  &:hover {
    background-color: #f8f9fa;
  }

  &.is-current {
    background-color: #e6f3ff;
  }

  &.is-editing {
    background-color: #fff7e6;
  }
}

.row-content {
  display: flex;
  min-height: 48px;
  align-items: stretch;
}

.virtual-table-cell {
  flex: 1;
  padding: 8px 12px;
  border-right: 1px solid #f0f0f0;
  display: flex;
  align-items: center;

  &:last-child {
    border-right: none;
  }
}

.cell-content {
  width: 100%;
  min-height: 20px;
  outline: none;
  word-break: break-word;

  &.is-editable {
    cursor: text;

    &:hover {
      background-color: rgba(0, 100, 255, 0.05);
    }

    &:focus {
      outline: 2px solid #409eff;
      outline-offset: -1px;
      border-radius: 2px;
    }
  }

  &.is-editing {
    background-color: #fff;
    border-radius: 2px;
  }
}

.loading-mask {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(255, 255, 255, 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

.loading-spinner {
  padding: 20px;
  background-color: white;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
</style>
